#ifndef __TDP2_VISUALRESOURCES_HPP__
#define __TDP2_VISUALRESOURCES_HPP__

#include "../../rdx/src/rdx/rdx_basictypes.hpp"
#include "tdp2_math.hpp"
#include "tdp2_liveresource.hpp"
#include "tdp2_visualresources_enums.hpp"

namespace RDX
{
	namespace Programmability
	{
		class String;
	};

	namespace ObjectManagement
	{
		struct INativeTypeHost;
	}
};



namespace TDP
{
	using namespace RDX;
	using namespace RDX::Programmability;

	namespace Resources
	{
		namespace ShaderInfo
		{
			struct ShaderInfo;
			class Technique;
		}
	};

	// NOTE: This must match EngineRendererBuiltins.rdx
	namespace Rendering
	{
		enum VarSource
		{
			VARS_None,
			VARS_ModelMatrix,
			VARS_MVPMatrix,
			VARS_CameraPosition,
			VARS_FogPlane,
			VARS_FogColor,
			VARS_LightMapC,
			VARS_LightMapLQ,
			VARS_Fog,
			VARS_CameraInFog,
		};

		class TechniqueSet
		{
		public:
			Resources::ShaderInfo::Technique *worldBase;
		};

		enum MaterialType
		{
			MATT_UIGraphic,
			MATT_WorldSurfaceGeneric,
		};
	}

	namespace Resources
	{
		struct ResourceBundle;
		struct Material;

		// Search for "PackedWorldVertex" if this is changed to make sure data emitters still work
		struct PackedWorldVertex
		{
			Math::FVec3 position;
			Math::FVec2 texCoords;
			Math::FVec2 lmTexCoords;
			Math::FVec3 svec;
			Math::FVec4 tvecN;
			UInt8 rgbShadow[4];
		};

		struct StreamableResource
		{
			struct NativeProperties
			{
				Resources::LiveResourceHandle resHandle;
				Resources::ResourceType lrhType;
				StreamableResource *previousResource;
				StreamableResource *nextResource;
			} _native;
		};

		struct BundledResource : public StreamableResource
		{
			ResourceBundle *owner;
			Int resourceIndex;
			Int dataOffset;
		};

		struct BundledGeometryData : public BundledResource
		{
			enum
			{
				VF_WorldVertex,
				VF_SkeletalVertex,
			};
			
			struct Segment
			{
				Int numVerts;
				Int numTris;
			};

			struct Cluster
			{
				Segment *segments;
			};

			EnumValue format;
			Cluster *clusters;
		};
		
		struct BundledTexture : public BundledResource
		{
			EnumValue format;
			EnumValue layout;
			Int numMipMaps;		// Number of mipmap levels
			Int cachedMipMaps;	// Number of mipmaps in the cache
			Int width;
			Int height;
			Int depth;
			Bool sRGB;
			Bool autoMipMap;

			const String *highResFile;
		};

		struct BundledCompiledShader : public BundledResource
		{
			EnumValue shaderType;
			Int sizeBytes;
		};

		struct ResourceBundle : public StreamableResource
		{
			const String *binaryFileName;
			BundledResource **resources;
		};

		struct WorldModel
		{
			struct CSGInfo
			{
				struct SolidBrush
				{
					Int *sides;
				};

				struct SolidLeaf
				{
					Int *brushes;
				};

				SolidBrush *brushes;
				SolidLeaf *leafs;
			};

			struct VolumetricEffect
			{
				Int *boundingPlanes;
				Int surfacePlaneIndex;	// -1 = unbounded
				Math::FVec3 fogColor;
				Float fogDensityScalar;
				Float transitionDepth;
				Int sceneVolume;
			};

			struct PrimaryLight
			{
				Math::FVec3 origin;
				Math::FVec3 direction;
				Math::FVec3 emission;

				Bool isSky;
			};

			struct GeometrySegmentInfo
			{
				Int numVerts;
				Int numTris;
				Math::FBounds3 bounds;

				Bool planeSideCull;
				Math::FPlane3 plane;

				Int volumetricEffectIndex;	// -1 = no volumetric effect
				Int originalFaceIndex;
				Int originalChartIndex;
				Int lightMapIndex;
				Int primaryLightIndex;

				BundledTexture *lightMapCTexture;
				BundledTexture *lightMapLQTexture;
				BundledTexture *lightMapSimpleTexture;
				
				BundledTexture *lightMapB1Texture;
				BundledTexture *lightMapB2Texture;
				BundledTexture *lightMapB3Texture;
				BundledTexture *lightMapSGCTexture;
				BundledTexture *lightMapSGDTexture;

				BundledTexture *environmentMapTexture;

				Bool clippedToVolumetrics;

				Bool lodControl;
				Bool lodHasMax;
				Math::FVec3 lodOrigin;
				Float lodMin;
				Float lodMax;
			};

			struct GeometryClusterInfo
			{
				GeometrySegmentInfo *segmentInfos;
				Material *material;
				Int bundleClusterIndex;
			};

			struct Model
			{
				GeometryClusterInfo *clusterInfos;
				Int firstCluster;
			};

			struct Leaf
			{
				Int cluster;
				Int zone;
				Math::FBounds3 bounds;
				Int firstMarkFace;
				Int numMarkFaces;
			};

			struct Node
			{
				Int planeIndex;
				Int frontChild;		// <= 0:  =Leaf[-(frontChild+1)]
				Int backChild;		// <= 0:  =Leaf[-(backChild+1)]
				Math::FBounds3 bounds;
			};

			struct Material
			{
				const BundledTexture *usedTextures;
				const EnumValue materialType;
			};

			struct Zone
			{
				Bool reversePortals;
				Int *portalIndexes;
				Int *leafs;
			};
			
			struct ZonePortal
			{
				Int planeIndex;
				Int zones[2];
				Math::FVec3 *windingPoints;
			};

			Int numFaces;
			Int numCharts;
			Int numLightmaps;
			Int numScenes;
			Int numClusters;

			Math::FVec3 gridSize;
			Math::FVec3 gridOrigin;
			Int gridSizeX;
			Int gridSizeY;
			Int gridSizeZ;
			Float gridScalar;

			Int visRowWidth;
			Byte *visibilityData;

			Int *faceSmoothingGroups;

			Math::FPlane3 *planes;
			Int *markFaces;
			Leaf *leafs;
			Node *nodes;
			VolumetricEffect *volumetricEffects;
			Model *models;
			Zone *zones;
			ZonePortal *zonePortals;
			PrimaryLight *primaryLights;
			
			BundledGeometryData *geometryData;
		};

		namespace ShaderInfo
		{

			enum VarType
			{
				VT_Sampler2D,
				VT_Sampler3D,
				VT_SamplerRECT,
				VT_SamplerCUBE,
				VT_Float,
				VT_Float2,
				VT_Float3,
				VT_Float4,
				VT_Float2x2,
				VT_Float3x3,
				VT_Float4x4,
			};

			struct TextureSource
			{
				EnumValue samplerType;
			};

			class Technique
			{
			public:
				struct UniformSource
				{
					EnumValue builtinVarSource;
					Int textureSourceIndex;
				};

				struct Uniform
				{
					const String		*uniformName;
					const EnumValue		varType;
					Int					firstSource;
					Int					numSources;
				};

				struct PermutationNode
				{
					enum PermutationType
					{
						PT_TexturePresent,
						PT_FloatValueAtLeast,
					};

					EnumValue	permutationType;
					Float		comparison;
					Int			sourceIndex;
					Int			trueBranch;
					Int			falseBranch;
				};

				struct PermutationLeaf
				{
					Int	vertexShaderSource;
					Int	pixelShaderSource;
					Int	geometryShaderSource;
				};

				struct CompiledShaderRef
				{
					BundledCompiledShader	*shader;
				};

				Uniform *uniforms;
				UniformSource *uniformSources;
				PermutationNode *permutationNodes;
				PermutationLeaf *permutationLeafs;
				CompiledShaderRef *compiledShaders;
			};

			struct ShaderInfo
			{
				Rendering::TechniqueSet *techniqueSet;
				TextureSource *textureSources;
			};
		}

		const RDX::ObjectManagement::INativeTypeHost *GetVisualResourcesPluginDetached();
		const RDX::ObjectManagement::INativeTypeHost *GetVisualResourcesPluginIntegrated();
	};
};

#endif
